
import sys
import time
import re
import json
import threading
import requests
import os

from PySide6.QtWidgets import (QApplication, QMainWindow, QLabel,
                               QWidget, QVBoxLayout, QMessageBox)
from PySide6.QtCore import Qt, Signal, QObject
from PySide6.QtGui import  QPixmap
from io import BytesIO

from PIL import Image
from PIL.ImageQt import ImageQt

os.chdir(os.path.dirname(__file__))
# --------------------------------------------------
# 网络层：
# --------------------------------------------------
class WPSLoginBackend(QObject):
    set_qc  = Signal(QPixmap)
    scanned = Signal()          # 已扫码
    logined = Signal(dict)      # 已确认，回传 cookies
    error   = Signal(str)       # 任意一步失败

    def __init__(self, parent=None):
        super().__init__(parent)
        self._stop = False
        self.sess = requests.Session()

    def start(self):
        threading.Thread(target=self._work, daemon=True).start()

    def stop(self):
        self._stop = True

    # ---------- 主流程 ----------
    def _work(self):
        try:
            # 1. 申请二维码
            url, channel_id = self._get_qr_url()
            self.qr_url = url
            self.channel_id = channel_id
            # 2. 轮询扫码状态
            while not self._stop:
                st, ssid = self._query_status(channel_id)
                if st == "scan":
                    self.scanned.emit()
                elif st == "finish":
                    cookies = self._finish_login(ssid)
                    self.logined.emit(cookies)
                    return
                time.sleep(1)
        except Exception as e:
            self.error.emit(str(e))

    # ---------- 接口细节 ----------
    def _get_qr_url(self):
        # 1. 当场生成时间戳
        ts = str(int(time.time() * 1000))
        # 2. 固定参数
        params = {
            "action": "verify",
            "mpappid": "wx5b97b0686831c076",      # 目前固定
            "data": '{"qrShowAgreement":true,"keeponline":1,"from":"v1-wap-wps-login"}',
            "_": ts
        }
        headers = {
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0",
            "Referer": "https://account.wps.cn/",
            "X-Requested-With": "XMLHttpRequest"
        }
        # 3. 申请二维码
        url = "https://account.wps.cn/api/v3/miniprogram/code/img"
        r = requests.get(url, headers=headers, params=params, timeout=10)
        r.raise_for_status()
        j = r.json()
        # 2. 立刻下载图片
        qr_bytes = requests.get(j["url"], headers=headers, timeout=10).content
        self.set_qc.emit(QPixmap.fromImage(ImageQt(Image.open(BytesIO(qr_bytes)))))
        return j["url"], j["channel_id"]


    def _query_status(self, channel_id: str) -> str:
        #"""返回 state 字符串：scanning / notified / ok / expired ..."""
        url = "https://qr.wps.cn/api/v3/channel/wait"
        params = {
            "_jsonp": "miniprogramcodeJsonpCallback",
            "channel_id": channel_id,
            "_": str(int(time.time() * 1000)),
            "callback": "miniprogramcodeJsonpCallback"
        }
        r = self.sess.get(url, params=params, timeout=1000)
        # 1. 摘括号里的 JSON
        json_str = re.search(r'^\w+\((.*)\)$', r.text.strip()).group(1)
        print(json_str)
        # 2. 转 dict
        obj = json.loads(json_str)
        # 3. 取字段
        state = obj['state']               # 'notified'
        result = obj['result']
        if(state == "notified") :
            inner_data = json.loads(obj['data'])    # data 本身是双重转义 JSON
            status = inner_data['data']['status']  # 'scan' 或 'finish'
            ssid = inner_data['data'].get('ssid')  # 只有 finish 才有
        else:
            status = "null"
            ssid = "null"
        return status, ssid

    def _finish_login(self, ssid: str):
        """拉完最后几步，返回 cookies dict"""
        # 1. 拿 ssid
        ts = str(int(time.time() * 1000))
        # 2. 选账号
        url = "https://account.wps.cn/api/v3/login/users"
        params = {"ssid": ssid, "filter_rule": "normal", "check_rule": "second_phone", "_": ts}
        r = self.sess.get(url, params=params, timeout=10)
        userid = r.json()["users"][0]["userid"]
        print("userid=", userid)
        # 3. 确认登录
        url = "https://account.wps.cn/passport/secure/api/login"
        data = {
            "userids": userid,
            "ssid": ssid,
            "ssid_sign": "WzNhhmtFiL2YXX8hQzwXHazkZXQani88BkK8-iD8abSXVwjJs9RtzWCO0DosGvpVAyiZMAf2J7VrrDjNUbwJSg",
            "public_key": "AKLTs2eC4ZF8RGxjm2z1KBft",
            "from": "v1-web-kdocs-login",
            "page": "weblogin_v2",
            "slv": "ecdsa_itk",
            "append_only": "false"
        }
        r = self.sess.post(url, data=data, timeout=10)
        print(r.json())
        r.raise_for_status()
        return dict(self.sess.cookies)   # 关键 cookie: wps_sid


# --------------------------------------------------
# UI：负责显示二维码 + 状态文字
# --------------------------------------------------
class LoginWindow(QWidget):
    def __init__(self, backend: WPSLoginBackend):
        super().__init__()
        self.backend = backend
        self.setWindowTitle("WPS 扫码登录")
        self.resize(280, 300)
        self.label = QLabel("正在获取二维码…", self)
        self.label.setScaledContents(True)      # 图片随 Label 大小自动缩放
        self.label.setAlignment(Qt.AlignCenter)
        lay = QVBoxLayout(self)
        lay.addWidget(self.label)
        # 信号连接
        backend.scanned.connect(self.on_scanned)
        backend.logined.connect(self.on_logined)
        backend.error.connect(self.on_error)
        backend.set_qc.connect(self.set_qr)
        # # 启动后端
        backend.start()

    # 显示二维码 QPixmap 并显示
    def set_qr(self, QPixmap: QPixmap):
        self.label.setPixmap(QPixmap)

    def on_scanned(self):
        QMessageBox.information(self, "提示", "已扫码，请在手机点击确认")

    def on_logined(self, cookies: dict):
        QMessageBox.information(self, "成功", "登录成功！")
        self.close()

    def on_error(self, txt: str):
        QMessageBox.critical(self, "错误", txt)
        self.close()


if __name__ == '__main__':
    app = QApplication(sys.argv)

    backend = WPSLoginBackend()
    login = LoginWindow(backend)
    login.show()
    sys.exit(app.exec())